
package com.studiofortress.sf.util.collections;

import com.studiofortress.sf.util.ArrayUtil;

/**
 * The intStack is a stack designed specifically for storing int values.
 * The idea is simply that it uses very little overhead and features.
 *
 * @author Joseph Lenton
 */
public class IntStack
{
    private static final int INITIAL_SIZE = 10;
    private int[] stack;
    private int size;

    /**
     * Trivial constructor for setting up a new stack.
     */
    public IntStack()
    {
        this(INITIAL_SIZE);
    }

    /**
     * Creates a new stack which with space made to hold the given size.
     * @param initialSize The amount of space this stack should have by default.
     */
    public IntStack(int initialSize)
    {
        stack = new int[initialSize];
        size = 0;
    }

    /**
     * @return The number of elements stored in this stack.
     */
    public int size()
    {
        return size;
    }

    /**
     * @param bool Adds this int to the top of this stack.
     */
    public void push(int bool)
    {
        ensureSize();
        stack[size++] = bool;
    }

    /**
     * @return The top element on this stack which is also permanently removed.
     */
    public int pop()
    {
        if (size <= 0) {
            throw new ArrayIndexOutOfBoundsException("Cannot pop, the stack is empty!");
        }

        return stack[--size];
    }

    /**
     * Ensures that there is enough size for at least one more element to be
     * added to this stack.
     */
    private void ensureSize()
    {
        if (stack.length == size) {
            stack = ArrayUtil.copyOf(stack, (size*4) / 3);
        }
    }

    /**
     * Removes all the elements from this stack.
     */
    /* Ok, it doesn't really remove them. But if space is an issue they can use
     * compact and this is far more efficient then clearing the stack. */
    public void clear()
    {
        size = 0;
    }

    /**
     * @return The value on the top of the stack.
     */
    public int peek()
    {
        return peek(0);
    }

    /**
     * @param index The index to get the int from, begins at 0.
     * @return The int stored at the given index.
     */
    public int peek(int index)
    {
        if (index < 0 || index >= size) {
            throw new ArrayIndexOutOfBoundsException("Invalid index given: " + index);
        }

        return stack[index];
    }

    /**
     * Compacts the internal data structures down so they use as little space
     * as possible. No elements are removed by this operation.
     *
     * Ideally this should be called if the stack has had a very large number
     * of elements added, which have now been removed and will not be readded.
     */
    public void compact()
    {
        stack = ArrayUtil.copyOf(stack, size);
    }
}
